﻿using JzSport.Model.Strategies;
using JzSport.Model.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JzSport.Model
{
    /// <summary>
    /// 账号服务
    /// </summary>
    public class AccountService
    {
        IValidationStrategy _validationStrategy = new ValidationStrategy();
        ICryptoSecurityStrategy _cryptoSecurityStrategy = new CryptoSecurityStrategy();

        /// <summary>
        /// 导入用户
        /// </summary>
        /// <param name="phone"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public ServiceResult<Account> Import(string phone, string password)
        {
            if (!_validationStrategy.ValidatePhone(phone))
            {
                return new ServiceResult<Account>(ErrorCode.Register_InvalidPhone);
            }

            if (!_validationStrategy.ValidatePassword(password))
            {
                return new ServiceResult<Account>(ErrorCode.Register_InvalidPassword);
            }

            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                ConfigRepository configReps = new ConfigRepository(dbContext);

                Config config = configReps.Get(ConfigCode.AccountId_Seed);

                Account account = reps.GetByPhone(phone);
                if (account != null)
                {
                    // 电话已注册
                    return new ServiceResult<Account>(ErrorCode.Register_PhoneRegistered);
                }

                // 创建账号
                account = new Account();
                account.Id = config.GetIntValue() + 1;
                account.Name = phone;
                account.Phone = phone;
                account.Password = Md5Util.ToMd5(password);
                account.CreatedDate = DateTime.Now;
                account.IsLocked = false;
                account.Sex = 1;
                account.AvatarUrl = Configs.DefaultAvatarUrl;
                account.NickName = string.Format("U{0}", phone);

                reps.Create(account);

                // 更新账户id种子
                config.Value = account.Id.ToString();
                configReps.Save(config);


                int resultCount = dbContext.SaveChanges();
                if (resultCount > 0)
                {
                    return new ServiceResult<Account>(ErrorCode.NoError, account);
                }
                else
                {
                    return new ServiceResult<Account>(ErrorCode.Register_CreateAccountError);
                }
            }
        }

        /// <summary>
        /// 通过手机好吗注册
        /// 验证：
        /// 判断手机号码是否合法，
        /// 判断密码是否合法
        /// 判断验证码是否合格
        /// 判断手机号码是否被注册
        /// </summary>
        /// <param name="phone"></param>
        /// <param name="password"></param>
        /// <param name="verifycode"></param>
        /// <returns></returns>
        public ServiceResult<Account> RegisterByPhone(string phone, string password, string verifycode)
        {
            if (!_validationStrategy.ValidatePhone(phone))
            {
                return new ServiceResult<Account>(ErrorCode.Register_InvalidPhone);
            }

            if (!_validationStrategy.ValidatePassword(password))
            {
                return new ServiceResult<Account>(ErrorCode.Register_InvalidPassword);
            }

            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                ConfigRepository configReps = new ConfigRepository(dbContext);
                VerifycodeRepository verifycodeReps = new VerifycodeRepository(dbContext);
                MessageRepository msgReps = new MessageRepository(dbContext);
                MessageClipRepository msgSetReps = new MessageClipRepository(dbContext);

                Verifycode verifycodeInDB = verifycodeReps.GetByPhone(phone, UsageCode.Register);

                if (verifycodeInDB == null
                    || verifycodeInDB.TimeoutTime <= DateTime.Now
                    || !string.Equals(verifycodeInDB.Value, verifycode, StringComparison.CurrentCultureIgnoreCase))
                {
                    return new ServiceResult<Account>(ErrorCode.Register_InvalidVerifycode);
                }

                Config config = configReps.Get(ConfigCode.AccountId_Seed);

                Account account = reps.GetByPhone(phone);
                if (account != null)
                {
                    // 电话已注册
                    return new ServiceResult<Account>(ErrorCode.Register_PhoneRegistered);
                }

                // 创建账号
                account = new Account();
                account.Id = config.GetIntValue() + 1;
                account.Name = phone;
                account.Phone = phone;
                account.Password = Md5Util.ToMd5(password);
                account.CreatedDate = DateTime.Now;
                account.NickName = string.Format("U{0}", phone);
                account.IsLocked = false;
                account.AvatarUrl = Configs.DefaultAvatarUrl;

                reps.Create(account);

                // 更新账户id种子
                config.Value = account.Id.ToString();
                configReps.Save(config);

                // 删除注册验证码
                verifycodeReps.Delete(verifycodeInDB);

                // 生成系统消息
                Message sysMessage = new Message();
                sysMessage.Id = Guid.NewGuid();
                sysMessage.Type = BasicData.MessageType.SystemNotice;
                sysMessage.ReceiverId = account.Id;
                sysMessage.SenderId = 0;
                sysMessage.Title = "欢迎使用[不健不散]!";
                sysMessage.Content = "欢迎使用[不健不散]!";
                sysMessage.CreatedTime = DateTime.Now;

                // 生成MessageSet
                MessageClip messageSet = new MessageClip();
                messageSet.Id = Guid.NewGuid();
                messageSet.IdentityText = sysMessage.Id.ToString("D");
                messageSet.Type = BasicData.MessageClipType.SystemNotice;
                messageSet.ReceiverId = sysMessage.ReceiverId;
                messageSet.MessageCount = 1;
                messageSet.NewMessageCount = 1;
                messageSet.CreatedTime = sysMessage.CreatedTime;
                messageSet.LastestSenderId = sysMessage.SenderId;
                messageSet.LastestContent = sysMessage.Content;
                messageSet.LastestTitle = sysMessage.Title;
                messageSet.LastestUpdatedTime = sysMessage.CreatedTime;

                msgSetReps.Create(messageSet);
                msgReps.Create(sysMessage);
                

                int resultCount = dbContext.SaveChanges();
                if (resultCount > 0)
                {
                    return new ServiceResult<Account>(ErrorCode.NoError, account);
                }
                else
                {
                    return new ServiceResult<Account>(ErrorCode.Register_CreateAccountError);
                }
            }
        }

        /// <summary>
        /// 通过第三方账号注册
        /// </summary>
        /// <param name="thirdPartyType"></param>
        /// <param name="thirdPartyAccount"></param>
        /// <param name="phone"></param>
        /// <returns></returns>
        public Account RegisterByThirdParty(string thirdPartyType, string thirdPartyAccount, string phone)
        {
            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                ConfigRepository configReps = new ConfigRepository(dbContext);

                Config config = configReps.Get(ConfigCode.AccountId_Seed);
                Account account = reps.GetByPhone(phone);
                if (account != null)
                {
                    // 电话已注册
                    return null;
                }

                // 创建账号
                account = new Account();
                account.Id = config.GetIntValue() + 1;
                account.Name = string.Format("{0}{1}", thirdPartyType, thirdPartyAccount);
                account.Phone = phone;
                account.Password = Md5Util.ToMd5("jizsoft");
                account.CreatedDate = DateTime.Now;
                account.ThirdPartyType = thirdPartyType;
                account.ThirdPartyAccount = thirdPartyAccount;
                account.IsLocked = false;
                reps.Create(account);

                config.Value = account.Id.ToString();
                configReps.Save(config);

                if (dbContext.SaveChanges() == 2)
                {
                    return account;
                }
            }
            return null;
        }

        /// <summary>
        /// 使用手机号码登录
        /// </summary>
        /// <param name="phone"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public ServiceResult<LoginResult> LoginByPhone(string phone, string password)
        {
            if (!_validationStrategy.ValidatePhone(phone))
            {
                // 无效的手机号码
                return new ServiceResult<LoginResult>(ErrorCode.Login_InvalidPhone);
            }

            if (!_validationStrategy.ValidatePassword(password))
            {
                // 无效的密码
                return new ServiceResult<LoginResult>(ErrorCode.Login_InvalidPassword);
            }

            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                Account account = reps.GetByPhone(phone);
                if (account == null)
                {
                    // 账号不存在
                    return new ServiceResult<LoginResult>(ErrorCode.Login_PhoneNotRegistered, null);
                }

                if (account.Password != Md5Util.ToMd5(password))
                {
                    // 密码错误，密码保护策略执行操作
                    LockResult lockResult =  _cryptoSecurityStrategy.IncorrectPassword(dbContext, account);

                    // 提交更改
                    if (dbContext.SaveChanges() > 0)
                    {
                        LoginResult result = new LoginResult();
                        if (!lockResult.IsLocked)
                        {
                            // 账号未锁定
                            result.RetryCount = lockResult.RetryCount;
                            result.UserId = 0;
                            result.Phone = string.Empty;
                            result.Name = string.Empty;
                            return new ServiceResult<LoginResult>(ErrorCode.Login_PasswordError, result);
                        }
                        else
                        {
                            // 账号已锁定
                            result.RetryCount = lockResult.RetryCount;
                            result.UserId = 0;
                            result.Phone = string.Empty;
                            result.Name = string.Empty;
                            result.LockoutDuration = lockResult.LockoutDuration;
                        }
                        return new ServiceResult<LoginResult>(ErrorCode.Login_Locked, result);
                    }
                    return new ServiceResult<LoginResult>(ErrorCode.DB_Error);
                }
                else
                {
                    if (account.IsLocked && DateTime.Now < account.UnlockTime)
                    {
                        // 账号已锁定，并且在锁定时间内
                        LoginResult result = new LoginResult();
                        result.RetryCount = 0;
                        result.UserId = 0;
                        result.Phone = string.Empty;
                        result.Name = string.Empty;
                        result.IsLocked = true;
                        result.LockoutDuration = (account.UnlockTime.Value - DateTime.Now).Minutes;
                        return new ServiceResult<LoginResult>(ErrorCode.Login_Locked, result);
                    }
                    else
                    {
                        // 账号登录成功
                        _cryptoSecurityStrategy.CorrectPassword(dbContext, account);
                        
                        // 提交更改
                        if (dbContext.SaveChanges() > 0)
                        {
                            LoginResult result = new LoginResult();
                            result.UserId = account.Id;
                            result.Phone = account.Phone;
                            result.Name = account.Name;
                            result.RetryCount = 0;
                            result.IsLocked = false;
                            result.Sex = account.Sex;
                            result.NickName = account.NickName;
                            result.City = account.City;
                            if (!string.IsNullOrEmpty(account.AvatarUrl))
                            {
                                result.AvatarUrl = account.AvatarUrl;
                            }
                            else
                            {
                                result.AvatarUrl = Configs.DefaultAvatarUrl;
                            }
                            return new ServiceResult<LoginResult>(ErrorCode.NoError, result);
                        }
                        return new ServiceResult<LoginResult>(ErrorCode.DB_Error);
                    }
                }
            }
        }

        /// <summary>
        /// 使用第三方账号登录
        /// </summary>
        /// <param name="thirdPartyType"></param>
        /// <param name="thirdPartyAccount"></param>
        /// <returns></returns>
        public Account LoginByThirdPartyAccount(string thirdPartyType, string thirdPartyAccount)
        {
            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                Account account = reps.GetByThirdPartyAccount(thirdPartyType, thirdPartyAccount);
                if (account != null)
                {
                    return account;
                }
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="phone"></param>
        /// <param name="password"></param>
        /// <param name="verifycode"></param>
        /// <returns></returns>
        public ServiceResult<Account> ChangePassword4ForgottenPassword(string phone, string password, string verifycode)
        {
            if (!_validationStrategy.ValidatePhone(phone))
            {
                return new ServiceResult<Account>(ErrorCode.ChangePassword_InvalidPhone);
            }

            if (!_validationStrategy.ValidatePassword(password))
            {
                return new ServiceResult<Account>(ErrorCode.ChangePassword_InvalidPassword);
            }

            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                ConfigRepository configReps = new ConfigRepository(dbContext);
                VerifycodeRepository verifycodeReps = new VerifycodeRepository(dbContext);


                Account account = reps.GetByPhone(phone);
                if (account == null)
                {
                    // 电话不存在
                    return new ServiceResult<Account>(ErrorCode.ChangePassword_PhoneUnregistered);
                }

                Verifycode verifycodeInDB = verifycodeReps.GetByPhone(phone, UsageCode.ForgottenPassword);

                if (verifycodeInDB == null
                    || verifycodeInDB.TimeoutTime <= DateTime.Now
                    || !string.Equals(verifycodeInDB.Value, verifycode, StringComparison.CurrentCultureIgnoreCase))
                {
                    return new ServiceResult<Account>(ErrorCode.ChangePassword_InvalidVerifycode);
                }

                // 修改密码
                account.Password = Md5Util.ToMd5(password);

                reps.Update(account.Id, account);

                int resultCount = dbContext.SaveChanges();
                if (resultCount > 0)
                {
                    return new ServiceResult<Account>(ErrorCode.NoError, account);
                }
                else
                {
                    return new ServiceResult<Account>(ErrorCode.DB_Error);
                }
            }
        }
        
        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="userId">用户id</param>
        /// <param name="oldPassword">旧密码</param>
        /// <param name="password">新密码</param>
        /// <returns></returns>
        public ServiceResult<Account> ChangePassword(int userId, string oldPassword, string password)
        {
            if (!_validationStrategy.ValidatePassword(oldPassword))
            {
                return new ServiceResult<Account>(ErrorCode.ChangePassword_InvalidPassword);
            }

            if (!_validationStrategy.ValidatePassword(password))
            {
                return new ServiceResult<Account>(ErrorCode.ChangePassword_InvalidPassword);
            }

            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                ConfigRepository configReps = new ConfigRepository(dbContext);
                Account account = reps.Get(userId);
                if (account == null)
                {
                    // 电话不存在
                    return new ServiceResult<Account>(ErrorCode.ChangePassword_PhoneUnregistered);
                }

                if (account.Password != Md5Util.ToMd5(oldPassword))
                {
                    // 旧密码不匹配
                    return new ServiceResult<Account>(ErrorCode.ChangePassword_PasswordError);
                }

                // 修改密码
                account.Password = Md5Util.ToMd5(password);

                reps.Update(account.Id, account);

                int resultCount = dbContext.SaveChanges();
                if (resultCount > 0)
                {
                    return new ServiceResult<Account>(ErrorCode.NoError, account);
                }
                else
                {
                    return new ServiceResult<Account>(ErrorCode.Register_CreateAccountError);
                }
            }
        }

        public ServiceResult<string> ChangeName(int userId, string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                return new ServiceResult<string>(ErrorCode.ChangeName_InvalidName);
            }
            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                ConfigRepository configReps = new ConfigRepository(dbContext);
                Account account = reps.Get(userId);
                if (account == null)
                {
                    // 电话不存在
                    return new ServiceResult<string>(ErrorCode.ChangeName_PhoneUnregistered);
                }

                // 修改密码
                account.Name = name;

                reps.Update(account.Id, account);

                int resultCount = dbContext.SaveChanges();
                if (resultCount > 0)
                {
                    return new ServiceResult<string>(ErrorCode.NoError, "修改成功");
                }
                else
                {
                    return new ServiceResult<string>(ErrorCode.DB_Error, "修改失败");
                }
            }
        }

        public ServiceResult<string> ChangeSex(int userId, int sex)
        {
            //if (string.IsNullOrEmpty(name))
            //{
            //    return new ServiceResult<string>(ErrorCode.ChangeName_InvalidName);
            //}
            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                ConfigRepository configReps = new ConfigRepository(dbContext);
                Account account = reps.Get(userId);
                if (account == null)
                {
                    // 电话不存在
                    return new ServiceResult<string>(ErrorCode.ChangeName_PhoneUnregistered);
                }

                // 修改密码
                account.Sex = sex;

                reps.Update(account.Id, account);

                int resultCount = dbContext.SaveChanges();
                if (resultCount > 0)
                {
                    return new ServiceResult<string>(ErrorCode.NoError, "修改成功");
                }
                else
                {
                    return new ServiceResult<string>(ErrorCode.DB_Error, "修改失败");
                }
            }
        }

        public ServiceResult<string> ChangeAvatar(int userId, string avatarUrl)
        {
            //if (string.IsNullOrEmpty(name))
            //{
            //    return new ServiceResult<string>(ErrorCode.ChangeName_InvalidName);
            //}
            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                ConfigRepository configReps = new ConfigRepository(dbContext);
                Account account = reps.Get(userId);
                if (account == null)
                {
                    // 电话不存在
                    return new ServiceResult<string>(ErrorCode.ChangeName_PhoneUnregistered);
                }

                // 修改密码
                account.AvatarUrl = avatarUrl;

                reps.Update(account.Id, account);

                int resultCount = dbContext.SaveChanges();
                if (resultCount > 0)
                {
                    return new ServiceResult<string>(ErrorCode.NoError, "修改成功");
                }
                else
                {
                    return new ServiceResult<string>(ErrorCode.DB_Error, "修改失败");
                }
            }
        }

        public ServiceResult<string> EditProfile(int userId, string nickName, int sex, string city)
        {
            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                IAccountRepository reps = new AccountRepository(dbContext);
                ConfigRepository configReps = new ConfigRepository(dbContext);
                Account account = reps.Get(userId);
                if (account == null)
                {
                    // 电话不存在
                    return new ServiceResult<string>(ErrorCode.ChangeName_PhoneUnregistered);
                }

                // 修改密码
                account.Sex = sex;
                account.NickName = nickName;
                account.City = city;

                reps.Update(account.Id, account);

                int resultCount = dbContext.SaveChanges();
                if (resultCount > 0)
                {
                    return new ServiceResult<string>(ErrorCode.NoError, "修改成功");
                }
                else
                {
                    return new ServiceResult<string>(ErrorCode.DB_Error, "修改失败");
                }
            }
        }

        //public ServiceResult<PagedList<Account>> Search(string filter, int start, int limit)
        //{
        //    if (string.IsNullOrEmpty(filter))
        //    {
        //        return new ServiceResult<PagedList<Account>>(ErrorCode.Common_InvalidParameter);
        //    }

        //    using (JzSportDbContext dbContext = new JzSportDbContext())
        //    {
        //        AccountRepository aRep = new AccountRepository(dbContext);

        //        PagedList<Account> pagedList = new PagedList<Account>();
        //        pagedList.Total = aRep.SearchCount(filter);
        //        pagedList.Items.AddRange(aRep.Search(filter, start, limit));
        //        pagedList.Start = start;
        //        pagedList.Limit = limit;

        //        return new ServiceResult<PagedList<Account>>(ErrorCode.NoError, pagedList);
        //    }
        //}

        /// <summary>
        /// 为用户查早用户
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="filter"></param>
        /// <param name="start"></param>
        /// <param name="limit"></param>
        /// <returns></returns>
        public ServiceResult<PagedList<Data.SearchUser4UserData>> Search4User(int userId, string filter, int start, int limit)
        {
            if (string.IsNullOrEmpty(filter))
            {
                return new ServiceResult<PagedList<Data.SearchUser4UserData>>(ErrorCode.Common_InvalidParameter);
            }

            using (JzSportDbContext dbContext = new JzSportDbContext())
            {
                AccountRepository aRep = new AccountRepository(dbContext);
                UserRelationRepository urReps = new UserRelationRepository(dbContext);

                List<Account> accounts = aRep.Search(userId, filter, start, limit);

                PagedList<Data.SearchUser4UserData> pagedList = new PagedList<Data.SearchUser4UserData>();
                pagedList.Total = aRep.SearchCount(userId, filter);
                for (int index = 0; index < accounts.Count; index++)
                {
                    Data.SearchUser4UserData data = new Data.SearchUser4UserData();
                    data.Account = accounts[index];
                    if (urReps.Get(userId, data.Account.Id, BasicData.UserRelationType.Friends, BasicData.UserRelationStatus.Established) != null)
                    {
                        data.IsFriend = true;
                    }
                    else
                    {
                        data.IsFriend = false;
                    }
                    pagedList.Items.Add(data);
                }
                pagedList.Start = start;
                pagedList.Limit = limit;

                return new ServiceResult<PagedList<Data.SearchUser4UserData>>(ErrorCode.NoError, pagedList);
            }
        }
    }
}
